<template>
    <div>
        <router-view v-slot="{ Component }">
        <!-- 根据不同name播放不同的动画
        当进入新页面时，name为push，执行新页面跳转动画
        进入旧页面时，name为back，执行返回动画 -->
            <transition :name="transitionName"
                @before-enter="beforeEnter"
                @after-leave="afterLeave"
            >
            <!-- include 控制缓存组件，是一个数组，里面元素是组件名称 -->
            <keep-alive :include="virtualTaskStack">
                <component :is="Component" :class="{ding:isAnimate}"/>
            </keep-alive>
                
            </transition>
        </router-view>
    </div>
</template>

<script>
// 常量通常是大写，定义一些不变的量
const ROUTER_TYPE_PUSH='push'
const ROUTER_TYPE_BACK='back'
const NONE = 'none'
const ROUTER_TYPE_ENUM=[ROUTER_TYPE_PUSH,ROUTER_TYPE_BACK,NONE]
</script>

<script setup>
import  { defineProps } from 'vue'
import {ref} from 'vue'
import { useRouter } from 'vue-router'
let transitionName=ref('')
let router=useRouter()
router.beforeEach((to,name)=>{
    // to是目的路由
    transitionName.value=props.routerType;
    // 以下进栈操作
    if (props.routerType==='ROUTER_TYPE_PUSH') {
        // 进栈操作
        virtualTaskStack.value.push(to.name)
    }else if(props.routerType==='ROUTER_TYPE_BACK'){
        // 出栈操作
        virtualTaskStack.value.pop(to.name)
    }
    if (to.name===props.mainComponentName){
        // 跳回首页，重置数组
        clearTask()
    }
})
// 需要一个标记，标记是新页面，要执行push动画
// 需要另外一个标记，标记是旧页面，执行back动画
let props= defineProps({
    // 如果routerType push back
    // 路由跳转的类型：push是进入组件，back是退出组件
    routerType:{
        type:String,
        default:NONE,
        validator(val){
            // 若设置跳转的过程中没有设置push或者back提示开发者
            // 保证开发者传递了routerType,以及只有push、back或者none
            const result=ROUTER_TYPE_ENUM.includes(val)
            if (!result) {
                throw new Error(`你的router_type必须是ROUTER_TYPE_ENUM的其中一个`)
            }
            return result
        }
    },
    mainComponentName:{
        type:String,
        required:true,
    }
})

let isAnimate=ref(false)
const beforeEnter=()=>{
    isAnimate=true
}
const afterLeave=()=>{
    isAnimate=false
}

// 初始化空的任务栈=>先把首页放在初始化数组中
let virtualTaskStack=ref([props.mainComponentName]);
const clearTask=()=>{
    virtualTaskStack.value=[props.mainComponentName]
}
</script>

<style lang="scss" scoped>
.ding{
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
}
// push页面时：新页面的进入动画.该知识点在vue动画的时候讲过
.push-enter-active {
  animation-name: push-in;
  animation-duration: 0.4s;
}
// push页面时：老页面的退出动画
.push-leave-active {
  animation-name: push-out;
  animation-duration: 0.4s;
}
// push页面时：新页面的进入动画
@keyframes push-in {
  0% {
    transform: translate(100%, 0);
  }
  100% {
    transform: translate(0, 0);
  }
}
// push页面时：老页面的退出动画
@keyframes push-out {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(-50%, 0);
  }
}

// 后退页面时：即将展示的页面动画
.back-enter-active {
  animation-name: back-in;
  animation-duration: 0.4s;
}
// 后退页面时：后退的页面执行的动画
.back-leave-active {
  animation-name: back-out;
  animation-duration: 0.4s;
}
// 后退页面时：即将展示的页面动画
@keyframes back-in {
  0% {
    width: 100%;
    transform: translate(-100%, 0);
  }
  100% {
    width: 100%;
    transform: translate(0, 0);
  }
}
// 后退页面时：后退的页面执行的动画
@keyframes back-out {
  0% {
    width: 100%;
    transform: translate(0, 0);
  }
  100% {
    width: 100%;
    transform: translate(50%, 0);
  }
}
</style>